# coding=utf-8
from string import Template

from utils.util import  writeFile

NetSomeIP_h=Template(
"""#pragma once
#include <memory>
#include <transfer/ITransfer.h>
namespace ecarx::transfer::someip {
class NetSomeIP:public ITransfer{
    class NetSomeIPImpl;
    NetSomeIPImpl* mSomeIpPtr;
    public:
        NetSomeIP();
        ~NetSomeIP();
        //打开链接
        bool open() override;
        //关闭链接
        bool close() override;
        //将数据写到网络上
        bool write(const Signal &) override;
        const std::optional<Signal> read(const int32_t signalId) const override;
        NetState getState() override;
        void onSignalChanged(SignalChangeCallback &&callback) override;
        void registerStateHandler(NetStateCallback && _callback) override;
};
}
"""
)

NetSomeIP_cpp = Template("""#define LOG_NDEBUG 0
#define LOG_TAG "NetSomeIP"
#include "someip/NetSomeIP.h"

#include "VHalLog.h"
#include <transfer/SafeQueue.h>
#include <transfer/SignalStorage.h>

#include <thread>

#include "ConvertSignal2SomeIP.h"
#include "ConvertSomeIP2Signal.h"
#include "SomeIPConfig.h"
namespace ecarx::transfer::someip {
//发送someip消息的线程
static utils::ConcurrentQueue<std::shared_ptr<vsomeip::message>> mSendMsgQueue;
static utils::BatchingConsumer<std::shared_ptr<vsomeip::message>> mBatchingConsumer;
// Signal池
static storage::SignalPool mMessageStorage;
static std::unordered_map<vsomeip::message_t, std::shared_ptr<vsomeip::message>> mMsgBuffer;

//探寻服务状态
static std::map<vsomeip::service_t, bool> mServiceAvailable;

class NetSomeIP::NetSomeIPImpl{
    std::shared_ptr<vsomeip::runtime> rtm_;
    std::shared_ptr<vsomeip::application> app_;
    SignalChangeCallback mSignalCallback = nullptr;
    NetStateCallback mStateCallback = nullptr;
    std::thread mSender;
    NetState mState;

  private:
    bool init() {
        if (!app_->init()) {
            VHALOG.d("Couldn't initialize application");
            return false;
        }
        // register a state handler to get called back after registration at the
        // runtime was successful
        app_->register_state_handler(
            std::bind(&NetSomeIPImpl::on_state_cbk, this, std::placeholders::_1));
        app_->register_message_handler(
            vsomeip::ANY_SERVICE, vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD,
            std::bind(&NetSomeIPImpl::on_message_cbk, this, std::placeholders::_1));

        for (auto& service_info : request_event_infos) {
            app_->register_availability_handler(
                service_info.service_id, ${instance_id},
                std::bind(&NetSomeIPImpl::on_availability_cbk, this, std::placeholders::_1,
                          std::placeholders::_2, std::placeholders::_3));
        }
        return true;
    }
    void start() {
        VHALOG.d("app_ start()");
        app_->start();
    }
    void stop() {
        VHALOG.d("stop method");
        // Stop offering the service
        for (auto& service_info : offer_service_infos) {
            app_->stop_offer_service(service_info.service_id, ${instance_id});
            for (auto& event_info : service_info.events) {
                //还要停止提供event
                std::set<vsomeip::eventgroup_t> offer_groups;
                offer_groups.insert(event_info.eventgroup_id);
                for (auto event_id : event_info.event_ids) {
                    app_->stop_offer_event(service_info.service_id, ${instance_id}, event_id);
                }
            }
        }
        for (auto& service_info : request_event_infos) {
            app_->release_service(service_info.service_id, ${instance_id});
            for (auto& event_info : service_info.events) {
                app_->unsubscribe(service_info.service_id, ${instance_id}, event_info.eventgroup_id);
            }
        }
        // unregister the state handler
        app_->unregister_state_handler();
        // unregister the message handler
        app_->unregister_message_handler(vsomeip::ANY_SERVICE, vsomeip::ANY_INSTANCE,
                                         vsomeip::ANY_METHOD);
        app_->clear_all_handler();
        // shutdown the application
        app_->stop();
        if (mSender.joinable()) {
            mSender.join();
        }
        mBatchingConsumer.requestStop();
        mSendMsgQueue.deactivate();
        mBatchingConsumer.waitStopped();
    }
    void on_state_cbk(vsomeip::state_type_e _state) {
        VHALOG.d("on_state_cbk _state %d ", (int8_t)_state);
        if (_state == vsomeip::state_type_e::ST_REGISTERED) {
            // we are registered at the runtime and can offer our service
            for (auto& service_info : offer_service_infos) {
                VHALOG.d("offer_service  %d", service_info.service_id);
                app_->offer_service(service_info.service_id, ${instance_id});
                for (auto& event_info : service_info.events) {
                    //还要提供event
                    std::set<vsomeip::eventgroup_t> offer_groups;
                    offer_groups.insert(event_info.eventgroup_id);
                    for (auto event_id : event_info.event_ids) {
                        VHALOG.d("offer_event  %d", event_id);
                        app_->offer_event(service_info.service_id, ${instance_id}, event_id, offer_groups);
                    }
                }
            }
            VHALOG.d("request_service size %zu", request_event_infos.size());
            //请求service和注册event
            for (auto& service_info : request_event_infos) {
                VHALOG.d("request_service 0x%x", service_info.service_id);
                app_->request_service(service_info.service_id, ${instance_id});
                for (auto& event_info : service_info.events) {
                    //请求并订阅event
                    std::set<vsomeip::eventgroup_t> request_groups;
                    request_groups.insert(event_info.eventgroup_id);
                    for (auto event_id : event_info.event_ids) {
                        VHALOG.d("request_event 0x%x", event_id);
                        app_->request_event(service_info.service_id, ${instance_id}, event_id, request_groups);
                    }
                    VHALOG.d("subscribe [0x%x.0x%x]", service_info.service_id, event_info.eventgroup_id);
                    // app_->register_subscription_error_handler(
                    //    service_info.service_id, ${instance_id}, event_info.eventgroup_id,
                    //    [](uint16_t status) {
                    //        VHALOG.d("register_subscription_error_handler cbk status %d", status);
                    //    });
                    app_->subscribe(service_info.service_id, ${instance_id}, event_info.eventgroup_id);
                }
            }
        } else {
            VHALOG.d("on_state_cbk error");
        }
    }
    void on_availability_cbk(vsomeip::service_t _service, vsomeip::instance_t _instance,
                             bool _is_available) {
        VHALOG.d("on_availability_cbk service %d instance %d is_available %d", _service, _instance,
              _is_available);
        //这里当请求的服务可用
        mServiceAvailable.insert_or_assign(_service, _is_available);
        bool allAvailable = true;
        for (auto& service_info : request_event_infos) {
            auto iter = mServiceAvailable.find(service_info.service_id);
            allAvailable = iter != mServiceAvailable.end() && iter->second;
            if (!allAvailable) {
                break;
            }
        }
        if (allAvailable) {
            notifyNetState(NetState::Ready);
        }
    }
    void on_message_cbk(const std::shared_ptr<vsomeip::message>& _request) {
        //当收到一条请求
        VHALOG.d(
            "on_message_cbk [%x.%x.%x.%x]: messageType: 0x%x, "
            "returnCode: 0x%x",
            _request->get_service(), _request->get_instance(), _request->get_method(),
            _request->get_session(), static_cast<int>(_request->get_message_type()),
            static_cast<int>(_request->get_return_code()));
        if (_request->get_service() == 707 && _request->get_method() == 0xa11) {
            // client getALL
            VHALOG.d("on_message_cbk client %d request get all notify size %lu",
                  _request->get_client(), mMsgBuffer.size());
            for (auto& kv : mMsgBuffer) {
                mSendMsgQueue.push(std::move(kv.second));
            }
        } else {
            std::vector<ecarx::transfer::Signal> buffer = someipToSignals(_request);
            std::vector<int32_t> changed;
            mMessageStorage.put(buffer,changed);
            VHALOG.d("on_message_cbk changed size %zu", changed.size());
            if (!changed.empty()) {
                mSignalCallback(changed);
            }
        }
    }
    void doSend(std::shared_ptr<vsomeip::message> msg) {
        //判断消息类型
        vsomeip::message_type_e msgType = msg->get_message_type();
        if (msgType == vsomeip::message_type_e::MT_NOTIFICATION) {
            app_->notify(msg->get_service(), msg->get_instance(), msg->get_method(),
                         msg->get_payload());
        } else {
            // MT_REQUEST_NO_RETURN
            app_->send(msg);
        }
    }
    void notifyNetState(NetState state) {
        mState = state;
        if (mStateCallback != nullptr) {
            mStateCallback(state);
        }
    }

  public:
    NetSomeIPImpl()
        : rtm_(vsomeip::runtime::get()), app_(rtm_->create_application("SomeIPFromSlaveService")) {
        mState = NetState::INIT;
        mBatchingConsumer.run(&mSendMsgQueue,
                              std::bind(&NetSomeIPImpl::doSend, this, std::placeholders::_1));
    }
    ~NetSomeIPImpl() { stop(); }
    //打开链接
    bool open() {
        notifyNetState(NetState::Open);
        VHALOG.d("start open");
        if (init()) {
            VHALOG.d("start SomeIP");
            mSender = std::thread(&NetSomeIPImpl::start, this);
            return true;
        }
        VHALOG.d("start error");
        notifyNetState(NetState::INIT);
        return false;
    }
    //关闭链接
    bool close() {
        notifyNetState(NetState::Close);
        stop();
        return true;
    }
    //将数据写到网络上
    bool write(const Signal& signal) {
        auto message = convertSignal2SomeipMessage(signal);
        VHALOG.d("write signal 0x%x [%d.%d.%d] payload size %d", message->get_message(),
              message->get_service(), message->get_method(), (int32_t)message->get_message_type(),
              message->get_payload()->get_length());

        if (message->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) {
            mMsgBuffer.insert_or_assign(message->get_message(), message);
            mSendMsgQueue.push(std::move(message));
            return true;
        } else {
            bool available = true;
            auto iter = mServiceAvailable.find(message->get_service());
            available = iter != mServiceAvailable.end() && iter->second;
            if (available) {
                mSendMsgQueue.push(std::move(message));
            } else {
                VHALOG.d("service id %d not available", message->get_service());
            }
            return available;
        }
    }
    const std::optional<Signal> read(const int32_t signalId) const  {
        return mMessageStorage.get(signalId);
    }

    NetState getState(){
        return mState;
    }

    void onSignalChanged(SignalChangeCallback&& callback)  { mSignalCallback = callback; }
    void registerStateHandler(NetStateCallback&& _callback)  { mStateCallback = _callback; }
};

NetSomeIP::NetSomeIP() : mSomeIpPtr(new NetSomeIPImpl()) {}

NetSomeIP::~NetSomeIP(){
    delete mSomeIpPtr;
}

//打开链接
bool NetSomeIP::open() {
    return mSomeIpPtr->open();
}
//关闭链接
bool NetSomeIP::close() {
    return mSomeIpPtr->close();
}
//将数据写到网络上
bool NetSomeIP::write(const Signal& signal) {
    return mSomeIpPtr->write(signal);
}
const std::optional<Signal> NetSomeIP::read(const int32_t signalId) const {
    return mSomeIpPtr->read(signalId);
}

NetState  NetSomeIP::getState(){
    return mSomeIpPtr->getState();
}

void NetSomeIP::onSignalChanged(SignalChangeCallback&& callback) {
    mSomeIpPtr->onSignalChanged(std::move(callback));
}
void NetSomeIP::registerStateHandler(NetStateCallback&& _callback) {
    mSomeIpPtr->registerStateHandler(std::move(_callback));
}

}  // namespace ecarx::net::someip
"""
)



def gen_NetSomeIP():
    writeFile("./data/transfer/libsomeip/include/someip", "NetSomeIP.h",lambda file:file.write(NetSomeIP_h.substitute()))
    writeFile("./data/transfer/libsomeip/src", "NetSomeIP.cpp",lambda file:file.write(NetSomeIP_cpp.substitute(instance_id="ADCU_HMI_INSTANCE_ID")))     
    
        

